#include <sys/syscall.h>
#include <sys/proc.h>
#include <sys/vmm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>

void __pthread_entry();

int pthread_make_default_attr(pthread_attr_t *attr)
{
    attr->stacksize = PTHREAD_STACKSIZE_DEF;
    attr->stackaddr = malloc(attr->stacksize);
    if (!attr->stackaddr)
        return -1;
    memset((void *)attr->stackaddr, 0, attr->stacksize);
    attr->detachstate = PTHREAD_CREATE_JOINABLE;
    return 0;
}

int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
{
    if (!thread || !start_routine)
    {
        _set_errno(EINVAL);
        return -1;
    }

    pthread_attr_t default_attr;
    if (!attr)
    {
        //auto alloc attr
        if (pthread_make_default_attr(&default_attr) < 0)
            return -1;
        attr = &default_attr;
    }
    //create thread
    pid_t pid = syscall4(pid_t, SYS_THREAD_CREATE, (uintptr_t)attr, (uintptr_t)(void *)start_routine, (uintptr_t)arg, (uintptr_t)__pthread_entry);
    if (pid < 0)
        return -1;
    *thread = pid; //return pid
    return 0;
}

void pthread_exit(void *ret)
{
    syscall1(int, SYS_THREAD_EXIT, (uintptr_t)ret);
}

void __pthread_exit(void *ret)
{
    pthread_exit(ret);
}

int pthread_detach(pthread_t thread)
{
    return syscall1(int, SYS_THREAD_DETACH, thread);
}

int pthread_join(pthread_t thread, void **thread_ret)
{
    return syscall2(int, SYS_THREAD_JOIN, thread, (uintptr_t)thread_ret);
}

pthread_t pthread_self()
{
    return (pthread_t)gettid();
}

//check two thread if equal
int pthread_equal(pthread_t thread1, pthread_t thread2)
{
    return thread1 == thread2;
}

int pthread_cancel(pthread_t thread)
{
    return syscall1(int, SYS_THREAD_CANNEL, thread);
}

int pthread_setcancelstate(int state, int *oldstate)
{
    return syscall2(int, SYS_THREAD_CANCELSTATUS, state, (uintptr_t)oldstate);
}

int pthread_setcanceltype(int type, int *oldtype)
{
    return syscall2(int, SYS_THREAD_CANCELTYPE, type, (uintptr_t)oldtype);
}

int pthread_tystcancel(void)
{
    return syscall0(int, SYS_THREAD_TESTCANCEL);
}

int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
{
    if (!attr)
        return EINVAL;
    *detachstate = attr->detachstate;
}

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
{
    if (!attr)
        return EINVAL;
    attr->detachstate = detachstate;
    return 0;
}

int pthread_attr_init(pthread_attr_t *attr)
{
    if (!attr)
        return EINVAL;
    attr->stacksize = PTHREAD_STACKSIZE_DEF;
    attr->stackaddr = NULL;
    attr->detachstate = PTHREAD_CREATE_JOINABLE;
}

int pthread_attr_destroy(pthread_attr_t *attr)
{
    if (!attr)
        return EINVAL;
    if (!attr->stackaddr)
        free(attr->stackaddr);
    attr->stackaddr = NULL;
    attr->stacksize = 0;
    attr->detachstate = 0;
    return 0;
}

int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
{
    if (!attr)
        return EINVAL;
    if (stacksize)
        *stacksize = attr->stacksize;
    return 0;
}

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
    if (!attr)
        return EINVAL;
    attr->stacksize = stacksize;
    return 0;
}

int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
{
    if (!attr)
        return EINVAL;
    if (stackaddr)
        *stackaddr = attr->stackaddr;
    return 0;
}

int pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr)
{
    if (!attr)
        return EINVAL;
    if (attr->stackaddr)
        free(attr->stackaddr);
    attr->stackaddr = addr;
    return 0;
}

//pthread autoclean function when exit
void _pthread_cleanup_push(void (*cleanup)(void *), void *arg)
{
}

void _pthread_cleanup_pop(int execute)
{
}